<?php
/**
 * Smithy PHP library
 *
 * LICENSE
 *
 * This source file is subject to the new BSD license that is bundled
 * with this package in the file LICENSE.txt.
 * Smithy is a free Zend Framework based PHP library.
 *
 * @category   Smithy
 * @package    Smithy_Model
 * @subpackage Value
 * @copyright  Copyright (c) 2008-2009 Kovács Tamás
 * @license    New BSD License
 * @version    $Id: Abstract.php ktamas $
 */


/**
 * A basic model value class.
 *
 * Defines a Java style value object, that aggregates a
 * Doctrine_Record data source.
 *
 * @author Kovács Tamás
 * @category Smithy
 * @package Smithy_Model
 * @subpackage Entity
 * @version 2.0
 */
abstract class Smithy_Model_Entity_Abstract
{
    /**
     * The gateway object.
     *
     * @var Smithy_Model_Gateway_Abstract
     */
    protected $_gateway = null;

    /**
     * The datasource object.
     *
     * @var array|IteratorAggregate|ArrayAccess|null
     */
    protected $_dataSource = null;


    /**
     * Constructor
     *
     * @param aarray|IteratorAggregate|ArrayAccess|null $data Data for the entity object. [OPTIONAL]
     * @param Smithy_Model_Gateway_Abstract|null $gateway [OPTIONAL]
     * @return void
     */
    public function __construct($data = null, $gateway = null)
    {
        $this->setGateway($gateway)
            ->populate($data);

        $this->init();
    }

    /**
     * Initialize entity object.
     *
     * @return void
     */
    public function init()
    {}

    /**
     * Populates the entity object
     *
     * @param array|ArrayAccess|Smithy_Model_Entity_Abstract|Zend_Config|null $data
     * @return Smithy_Model_Entity_Abstract
     * @throws Smithy_Model_Value_Exception
     */
    public function populate($data)
    {
        if ($data instanceof Smithy_Model_Entity_Abstract) {
            $data = $data->getDataSource();
        }

        if ($data instanceof Doctrine_Record) {
            $this->_dataSource = $data;
        } else {
            if ($data instanceof Zend_Config) {
                $data = $data->toArray();
            }

            if (!is_array($data) && null !== $data) {
                var_dump($data); exit();
                throw new Smithy_Model_Entity_Exception('Config must be an instance of Zend_Config or Doctrine_Record or Smithy_Model_Entity_Abstract or be an array.');
            }

            $this->_dataSource = $this->getTable()->create((array)$data);
        }

        return $this;
    }

    /**
     * Returns the value objects data source.
     *
     * @return Doctrine_Record
     */
    public function getDataSource()
    {
        return $this->_dataSource;
    }

    /**
     * Returns the gateway class.
     *
     * @return Smithy_Model_Gateway_Abstract
     */
    public function getGateway()
    {
        return $this->_gateway;
    }

    /**
     * Sets the gateway class.
     *
     * @param Smithy_Model_Gateway_Abstract $gateway
     * @return Webshop_Product
     */
    public function setGateway(Smithy_Model_Gateway_Abstract $gateway)
    {
        $this->_gateway = $gateway;
        return $this;
    }

    /**
     * Returns the value object's datasource as an array.
     *
     * @return array
     */
    public function toArray()
    {
        return null === $this->_dataSource ? array() : $this->_dataSource->toArray();
    }

    /**
     * Populates the value object from an associative array.
     *
     * @param array $data
     * @return Smithy_Model_Entity_Abstract
     */
    public function fromArray(array $data)
    {
        $this->populate($data);
        return $this;
    }

    /**
     * Saves the object to the datasource.
     *
     * @return array The primary keys.
     */
    public function save()
    {
        $this->_dataSource->save();
        return $this->_dataSource->identifier();
    }

    /**
     * Sets the given property.
     *
     * @return void
     */
    public function __set($name, $value)
    {
        $setMethod = 'set' . ucfirst(strtolower($name));
        if (method_exists($this, $setMethod)) {
            call_user_func(
                array($this, $setMethod),
                $value
            );
        }

        $this->_dataSource->$name = $value;
    }

    /**
     * Gets the given property.
     *
     * @return mixed
     */
    public function __get($name)
    {
        $setMethod = 'get' . ucfirst(strtolower($name));
        if (method_exists($this, $setMethod)) {
            return call_user_func(
                array($this, $setMethod),
                null
            );
        }

        return $this->_dataSource->$name;
    }

    /**
     * Checks if a datasource parameter is set.
     *
     * @param string $name
     * @return bool
     */
    public function __isset($name)
    {
        return isset($this->_dataSource->$name);
    }

    /**
     * Calls a method on the $_dataSource object.
     */
    public function __call($name, $arguments)
    {
        return call_user_func_array(
            array($this->_dataSource, $name),
            $arguments
        );
    }

    /**
     * Returns the entity object's table object.
     *
     * @return Doctrine_Table
     */
    public function getTable()
    {
        return $this->getGateway()->getTable();
    }

    /**
     * Returns the entity object's form.
     *
     * @return Smithy_Form
     */
    public function getForm()
    {
        return $this->getGateway()->getForm();
    }
}
